#ifndef ___INTERFACE_H
#define ___INTERFACE_H


#include "base.h"

class ICell;
class ICellNotify;
class ICellSet;
class ICandidate;
//解题技巧对象
class IHelper;
class Operation;

typedef vector<ICandidate *> ICandidates;
typedef vector<ICellSet * > ICellSets;
typedef vector<ICell *> ICells;
typedef vector<Operation> Operations;

//数格集合对象接口，作为对行列宫或者锯齿，对角线里数格的容器，容器内不应该出现重复数（注：基础规则在IPuzzle里实现）
class ICellSet:public IObject
{
public:
    virtual bool registerCell(ICell *)=0; //将一个数格添加到CellSet，CellSet用来表示行／列／宫
    virtual ICells getCells()=0;    //获取包含的数格列表(应该使得其中的数格坐标与数格顺序相符合，区块删除等需要此特性解题）
    virtual int getType()=0;        //获取数格集合对象的类型，类型会影响解题的算法过程
};

//候选数对象，用来记录所代表的候选数的状态
class ICandidate:public IObject
{
public:
    virtual int getValue() const =0;//获取候选数的状态标记，值可以是Candidate::STA_NONE,STA_TAG,STA_NORMAL
	virtual int setValue(int val)=0;//设置候选数的状态标记
};

//数独题的逻辑对象，实现基本的数独规则，抽取支持自动解题以及人工解题的接口操作
class IPuzzle:public IObject
{
public:
    virtual int loadPuzzle(const char *pszSudoku)=0; //从FormatNumber81,FormatMultiLine,FormatSimpleTable格式的题目里导入
    virtual const char* exportPuzzle(int nType=FormatNumber81)=0; //导出题目，还可以导出FormatFullTable,FormatFullTableStable格式
    virtual ICell *getCell(const Point &)=0; //获取指定坐标的数格对象
    virtual ICells getCells()=0;//取出全部的数格
    virtual ICellSets getCellSets(int)=0; //根据传入类型，获取指定的数格集合列表，比如全部行，全部列，全部宫，参数可以是CellSet::X,Y,Z
    virtual Number getNumber(const Point &)=0;//获取指定坐标的数值
    virtual Number setNumber(const Point &,Number num)=0;//设置指定坐标数值，不做其他影响
    virtual Number unsetNumber(const Point &,Number num)=0;//取消数值设置，会尽可能的恢复该数格的候选数状态。不做其他影响
    virtual Number chainSetNumber(const Point &,Number num)=0; //设置数值，并且触发链式反应，将其他数格的候选数自动排除，自动解题使用此接口
    virtual Number chainUnsetNumber(const Point &,Number num)=0;//取消设置数值，并且触发链式反应，将其他数格里能恢复的候选数恢复回来
    virtual int setCandidate(const Point & ,Number num,int tag)=0;//设置指定数格的指定候选数的状态，不做其他影响
    virtual bool hasCandidate(const Point &,Number)=0;//检查某数格是否设置了某候选数（STA_NORMAL状态）
    virtual bool chkNumber(const Point &,Number)=0;//检查某数格是否可以填某数（在使用ICell::connect()建立了连接的可见数格里没有数格已经填写此数）
    virtual int getStatus()=0;//返回数独题的状态：未完成但有效PuzzleIsPlaying，完成且有效PuzzleIsOver，存在错误PuzzleHasError
};

//数格逻辑对象
class ICell:public IObject
{
public:
    virtual int registerCellSet(ICellSet *)=0;//关联CellSet
    virtual Number getNumber() const =0; //获取数格数值，如果已经填数，返回填数值，否则返回0
    virtual Point getPoint()=0; //获取当前坐标值
    virtual Number setNumber(Number num)=0;//试图填写数值，不做其他影响，如果是0，则恢复为未填数的状态
    virtual int setCandidate(Number num,int tag)=0;//设置该数个的某个候选数的状态
    virtual int getCandidate(Number num)=0; //试图获取数格某个候选数的状态
    virtual ICandidates getCandidates()=0;//获取候选数列表
    virtual ICellSets getCellSets()=0;//获取关联的CellSet
    virtual ICellSet *getCellSet(int nType)=0;//获取指定类型的关联数格集合
    virtual void connect(ICell *)=0; //与其他数格建立连接，单向连接，只是将对方加到自己的列表里
    virtual ICells getConnectedCells()=0; //获取建立了连接的CellSet里的数格集合
};


//推导链节点对象定义（对复杂推导进行辅助）暂时未用到
class ChainNode:public IObject
{
public:
	Number cand;
};

//解题operation对象定义，使用该类来包装解题操作
class Operation:public IObject //一个Operation对象表示对某一个/组数格的一个/组数字可以进行的操作
{
public:
    virtual int getType(){ return nType;};//获取操作的类型
    virtual Points getPoints(){return pts;}; //获取操作的坐标列表
    virtual Numbers getNumbers(){return nums;}; //获取操作的数字列表
    virtual int getHelperID() { return nHelperID;} //获取技巧编号

    virtual void setHelper(int nHelperID){ this->nHelperID=nHelperID;}
    virtual void setDesc(string strDesc) { this->strDesc=strDesc;}
    virtual void setPoints(Points pts) {this->pts=pts;}
    virtual void setNumbers(Numbers nums) { this->nums=nums;}

    virtual void addPoint(Point pt) {this->pts.push_back(pt);}
    virtual void addNumber(Number num) { this->nums.push_back(num);}

    Operation(OpType typ,int nhid):nType(typ),nHelperID(nhid){}
    virtual const char *toString() {return strDesc.c_str();} //注意这里可能存在的问题
private:
    OpType nType;   //操作类型
    Points pts;     //相关操作坐标
    Numbers nums;   //相关操作数
    int nHelperID;  //所使用的技巧ID
    string strDesc; //描述信息
};

//解题对象，可以挂载不同的解题技巧来对逻辑数独对象进行自动解题
class ISolver:public IObject
{
public:
    //TODO:doSolve和doStep应该可以合并
    virtual int doSolve(IPuzzle *,Operations &) = 0 ; //对传入的Puzzle对象解题，并且返回解题结果以及解题过程（Operation列表）
    virtual int doStep(IPuzzle *,Operations &,int step=1)=0 ;//对传入的Puzzle进行若干步解题操作，并返回解题过程
    virtual Operations getTips(IPuzzle *,int nStep=1)=0 ;//获取一个提示，但是不进行解题操作，nStep为最多只需要的提示数，只是一个建议值
    virtual int registerHelper(IHelper *) = 0 ;//注册解题接口，顺序决定解题技巧优先级（未考虑其他的优先级权衡和重设优先级的需求）
};

//解题技巧对象
class IHelper:public IObject //操作指定的Puzlle，给出
{
public:
    virtual Operations getActions(IPuzzle *,int n=1 ) = 0 ; //获取一个解题操作集合（参数为期望数）
};

//整理全部的技巧ＩＤ
enum ID_HELPER_ENUM {
    Helper_Manual           //特殊项——人工手动解体，非技巧
    ,Helper_Singler_Number  //唯一数法
    ,Helper_IntersectionRemoval    //区块删除法
        };

#endif
